package rtl;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;
import javax.lang.model.type.ArrayType;

/**
 *
 * @author Arkanif
 */
public class UniversalVariable {

    private  base object;

    public void toBaseType(base Base) {
        this.resetType();
        this.object = Base;
        this._hasInt = false;
    }

    public base getBaseType() {
        return this.object;
    }
    public static base SgetBaseType(UniversalVariable v) {
        return v.object;
    }

    public UniversalVariable() {
        this.resetType();
        ArrayType = new HashMap();
    }
    public UniversalVariable getMe() {
        return this;
    }
    public static int getBool(UniversalVariable v) {
        if(v.hasInt())
            return getInt(v);
        else {
            if(v.isArray()){
                if(v.ArrayType.size()>0)
                    return 1;
                else 
                    return 0;
            }
            if(v.isString()){
                if(v.StringType.length()>0)
                    return 1;
                else
                    return 0;
            }
            return 0;
        }
    }
    private void resetType() {
        this._isInt=false;
        this._isString=false;
        this._isArray=false;
        this._hasInt=false;
    }
    public static UniversalVariable and(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(getBool(one)!=0 && getBool(two)!=0)
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable or(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(getBool(one)!=0 || getBool(two)!=0)
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable not(UniversalVariable one) {
        UniversalVariable v = new UniversalVariable();
        if(getBool(one)==0)
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable greater(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.hasInt() && two.hasInt() && getInt(one) > getInt(two))
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable less(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.hasInt() && two.hasInt() && getInt(one) < getInt(two))
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable equal(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.hasInt() && two.hasInt() && getInt(one) == getInt(two))
            v.toIntType(1);
        else {
            if (one.isString() && two.isString()) {
                //System.out.println(one.getString()+"="+two.getString());
                if(one.StringType.equals(two.StringType)) {
                    //System.out.println("ODINAKOVIE");
                    v.toIntType(1);
                }
                else {
                    //System.out.println("RAZNIE");
                    v.toIntType(0);
                }
            }
            else
                v.toIntType(0);
        }
        return v;
    }
    public static UniversalVariable ne(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = equal(one,two);
        return UniversalVariable.not(v);
    }
    public static UniversalVariable geq(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.hasInt() && two.hasInt() && getInt(one) >= getInt(two))
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable leq(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.hasInt() && two.hasInt() && getInt(one) <= getInt(two))
            v.toIntType(1);
        else
            v.toIntType(0);
        return v;
    }
    public static UniversalVariable typeEqual(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        if(one.isInt() && two.isInt() ){
            if(getInt(one) == getInt(two))
                v.toIntType(1);
            else
                v.toIntType(0);
        }
        else
                v.toIntType(0);
        return v;
    }
    /* Поля и методы, связанные с типом данных "целое число" */
    private int IntType;
    private boolean _isInt;
    public boolean isInt() {return this._isInt;}
    private boolean _hasInt;
    public boolean hasInt() {return this._hasInt;}
    public void toIntType(int value) {
        this.resetType();
        this.IntType=value;
        this.StringType=Integer.toString(value);
        this._isInt=true;
        this._hasInt=true;
    }
    public static int getInt(UniversalVariable v) {
        return v.IntType;
    }
    public static UniversalVariable invert(UniversalVariable v) {
        if(v.hasInt()) {
            UniversalVariable val = new UniversalVariable();
            val.toIntType(-getInt(v));
            return val;
        }
        return v;
        
    }
    public static UniversalVariable sum(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toIntType(getInt(one)+getInt(two));
        return v;
    }
    public static UniversalVariable sub(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toIntType(getInt(one)-getInt(two));
        return v;
    }
    public static UniversalVariable mul(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toIntType(getInt(one)*getInt(two));
        return v;
    }
    public static UniversalVariable div(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toIntType(getInt(one)/getInt(two));
        return v;
    }
    public static UniversalVariable mod(UniversalVariable one , UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toIntType(getInt(one)%getInt(two));
        return v;
    }
    
    /* Поля и методы, связанные с типом данных "строка" */
    private String StringType;
    private boolean _isString;
    public boolean isString() {return this._isString;}

    public void toStringType(String value) {
        this.resetType();
        this.StringType=value;
        
        try{
            Integer.parseInt(value);
            this.IntType = Integer.valueOf(value);
            this._hasInt=true;
        }
        catch(NumberFormatException e){
            this._hasInt=false;
        }

        this._isString=true;
    }

    public String getString() {
        return this.StringType;
    }
    public static UniversalVariable append(UniversalVariable one,UniversalVariable two) {
        UniversalVariable v = new UniversalVariable();
        v.toStringType(one.getString().concat(two.getString()));
        return v;
    }

    
    /* Поля и методы, связанные с типом данных "ассоциативный массив" */
    private HashMap ArrayType;
    private int maxKey;
    private boolean _isArray;
    public boolean isArray() { return this._isArray;}
    public static void addElement(UniversalVariable array,UniversalVariable key,UniversalVariable value) {
        array.addElement(key, value);
    }
    public void addElement(UniversalVariable key,UniversalVariable value) {
        //System.out.println("Adding key "+key.getString()+ " with value "+value.getString());
        UniversalVariable.removeElement(this, key);
        //ArrayType.remove(key);
        ArrayType.put(key, value);
        //System.out.println("Now at key "+key.getString()+ " we have "+UniversalVariable.getElement(this, key).getString());
        if(key.isInt() && getInt(key)>maxKey)
            maxKey=getInt(key);

        this._hasInt=false;
    }
    public void toArrayType() {
        this.resetType();
        this._isArray=true;
        this.maxKey=-1;
    }
    public void addElement(UniversalVariable value) {
        maxKey++;
        UniversalVariable v = new UniversalVariable();
        v.toIntType(maxKey);
        this.addElement(v, value);
        //ArrayType.put(v, value);

        this._hasInt=false;
    }
    public static UniversalVariable getCount(UniversalVariable array) {
        UniversalVariable v = new UniversalVariable();
        if(array.isArray())
            v.toIntType(array.ArrayType.size());
        return v;
    }
    public static UniversalVariable getElement(UniversalVariable array,UniversalVariable key) {
        
        UniversalVariable v = new UniversalVariable();
        Set keySet = array.ArrayType.keySet();
        Iterator iterator = keySet.iterator();
        while(iterator.hasNext()) {
            //System.out.println("1");
            UniversalVariable fk = (UniversalVariable) iterator.next();
            //System.out.println("2");
            if(key.hasInt() && fk.hasInt() && getInt(key)==getInt(fk))
                return (UniversalVariable) array.ArrayType.get(fk);
            else {
                //System.out.println("3");
                if(key.getString().equals(fk.getString())) {
                    //System.out.println("4");
                    return (UniversalVariable) array.ArrayType.get(fk);
                }
                //System.out.println("5");
            }
        }
        //System.out.println("6");
        return v;
    }
    public static UniversalVariable removeElement(UniversalVariable array,UniversalVariable key) {

        UniversalVariable v = new UniversalVariable();
        Set keySet = array.ArrayType.keySet();
        Iterator iterator = keySet.iterator();
        while(iterator.hasNext()) {
            //System.out.println("1");
            UniversalVariable fk = (UniversalVariable) iterator.next();
            //System.out.println("2");
            if(key.hasInt() && fk.hasInt() && getInt(key)==getInt(fk))
                return (UniversalVariable) array.ArrayType.remove(fk);
                //return (UniversalVariable) array.ArrayType.get(fk);
            else {
                //System.out.println("3");
                if(key.getString().equals(fk.getString())) {
                    //System.out.println("4");
                    return (UniversalVariable) array.ArrayType.remove(fk);
                    //return (UniversalVariable) array.ArrayType.get(fk);
                }
                //System.out.println("5");
            }
        }
        //System.out.println("6");
        return v;
    }
    


}
